package interceptcrossing.ui;

import interceptcrossing.Intercept;
import interceptcrossing.Intersection;
import interceptcrossing.IntersectionFinder;
import interceptcrossing.command.CommandManager;

import java.awt.*;
import java.util.*;
import java.util.List;

public class MainWindowDirector {

	private int currentInterceptIndex;
	private List<Intercept> intercepts;
	private Frame owner;
	private List<Listener> listeners;
	private CommandManager commandManager;

	public MainWindowDirector(Frame owner) {
		this.owner = owner;
		this.intercepts = Collections.synchronizedList(new ArrayList<Intercept>());
		this.listeners = new LinkedList<Listener>();
		this.currentInterceptIndex = 0;
		this.commandManager = new CommandManager();
	}

	public CommandManager getCommandManager() {
		return this.commandManager;
	}

	public void addListener(Listener listener) {
		if (listener != null && !this.listeners.contains(listener)) {
			this.listeners.add(listener);
		}
	}

	public void removeListener(Listener listener) {
		if (listener != null && this.listeners.contains(listener)) {
			this.listeners.remove(listener);
		}
	}

	public int interceptsCount() {
		return this.intercepts.size();
	}

	public boolean hasIntercepts() {
		return !this.intercepts.isEmpty();
	}

	public Intercept getCurrentIntercept() {
		return this.currentInterceptIndex >= 0 ?
			this.intercepts.get(this.currentInterceptIndex) : null;
	}

	public List<Intercept> getIntercepts() {
		List<Intercept> ret = new LinkedList<Intercept>();
		ret.addAll(this.intercepts);
		return ret;
	}

	public boolean hasIntercept(Intercept intercept) {
		return this.intercepts.contains(intercept);
	}

	public void addIntercept(Intercept intercept) {
		assert (!this.intercepts.contains(intercept));

		this.intercepts.add(intercept);

		for (Listener listener : this.listeners) {
			listener.interceptAdded(intercept);
		}

		this.changeCurrentIntercept(this.intercepts.size() - 1);
	}

	public void removeIntercept(Intercept intercept) {
		assert (this.intercepts.contains(intercept));

		int index = this.intercepts.indexOf(intercept);
		this.intercepts.remove(intercept);

		for (Listener listener : this.listeners) {
			listener.interceptRemoved(intercept);
		}

		if (index == this.currentInterceptIndex) {
			this.changeCurrentIntercept(-1);
		} else {
			this.changeCurrentIntercept(this.currentInterceptIndex - 1);
		}
	}

	public void interceptsGenerated(Collection<Intercept> intercepts) {
		//this.clearAllIntercepts();

		for (Intercept intercept : intercepts) {
			if (!this.hasIntercept(intercept)) {
				this.addIntercept(intercept);
			}
		}
	}

	public void clearIntercepts() {
		this.clearAllIntercepts();
	}

	public void findIntersections() {
		Set<Intersection> intersections
			= new IntersectionFinder(this.intercepts).getIntersections();

		for (Listener listener : this.listeners) {
			listener.intersectionsFound(intersections);
		}
	}

	public void changeCurrentIntercept(Intercept intercept) {
		this.changeCurrentIntercept(this.intercepts.indexOf(intercept));
	}

	public void changeCurrentIntercept(int index) {
		this.currentInterceptIndex = index;
		Intercept intercept = (index >= 0) ? this.intercepts.get(index) : null;

		for (Listener listener : this.listeners) {
			listener.currentInterceptChanged(index, intercept);
		}
	}

	private void clearAllIntercepts() {
		this.intercepts.clear();

		for (Listener listener : this.listeners) {
			listener.interceptsCleared();
		}

		this.changeCurrentIntercept(-1);
	}

	public static interface Listener {

		public void interceptAdded(Intercept intercept);

		public void interceptRemoved(Intercept intercept);

		public void interceptsCleared();

		public void intersectionsFound(Set<Intersection> intersections);

		public void currentInterceptChanged(int index, Intercept intercept);
	}

	public static class ListenerAdapter implements Listener {

		public void currentInterceptChanged(int index, Intercept intercept) {
		}

		public void interceptAdded(Intercept intercept) {
		}

		public void interceptRemoved(Intercept intercept) {
		}

		public void interceptsCleared() {
		}

		public void intersectionsFound(Set<Intersection> intersections) {
		}
	}
}
